package com.catmiw.mp3;

public class Header {
	/**
	 * MPEG版本MPEG-1。
	 */
	public static final int MPEG1 = 3;

	/**
	 * MPEG版本MPEG-2。
	 */
	public static final int MPEG2 = 2;

	/**
	 * MPEG版本MPEG-2.5（非官方版本）。
	 */
	public static final int MPEG25 = 0;
	/*
	 * 用lsf,layer,bitrate_index索引访问: bitrate[lsf][layer-1][bitrate_index]
	 */
	private static int[][][] bitrate = {
		{
			//MPEG-1
			//Layer I
			{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448},
			//Layer II
			{0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384},
			//Layer III
			{0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320}
		},
		{
			//MPEG-2/2.5
			//Layer I
			{0,32,48,56,64,80,96,112,128,144,160,176,192,224,256},
			//Layer II
			{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160},
			//Layer III
			{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160}
		}
	};

	/*
	 * samplingRate[verID][sampling_frequency]
	 */
	private static int[][] samplingRate = {
		{11025 , 12000 , 8000,0},	//MPEG-2.5
		{0,0,0,0,},					//reserved
		{22050, 24000, 16000 ,0},	//MPEG-2 (ISO/IEC 13818-3)
		{44100, 48000, 32000,0}		//MPEG-1 (ISO/IEC 11172-3)
	};


	private byte[] headdata;

	public byte[] getHeaddata() {
		return headdata;
	}

	public int getFramesize() {
		return framesize;
	}

	/*
	 * verID: 2-bit
	 * '00'  MPEG-2.5 (unofficial extension of MPEG-2);
	 * '01'  reserved;
	 * '10'  MPEG-2 (ISO/IEC 13818-3);
	 * '11'  MPEG-1 (ISO/IEC 11172-3).
	 */
	private int verID;

	/*
	 * layer: 2-bit
	 * '11'	 Layer I
	 * '10'	 Layer II
	 * '01'	 Layer III
	 * '00'	 reserved
	 * 
	 * 已换算layer=4-layer: 1--Layer I; 2--Layer II; 3--Layer III; 4--reserved
	 */
	private int layer;

	/*
	 * protection_bit: 1-bit
	 * '1'  no CRC;
	 * '0'  protected by 16-bit CRC following header.
	 */
	private int protection_bit;

	/* 
	 * bitrate_index: 4-bit
	 */
	private int bitrate_index;

	/*
	 * sampling_frequency: 2-bit
	 * '00'	 44.1kHz
	 * '01'	 48kHz
	 * '10'	 32kHz
	 * '11'  reserved
	 */
	private int sampling_frequency;

	private int padding;

	/*
	 * mode: 2-bit
	 * '00'  Stereo;
	 * '01'  Joint Stereo (Stereo);
	 * '10'  Dual channel (Two mono channels);
	 * '11'  Single channel (Mono).
	 */
	private int mode;

	/*
	 * mode_extension: 2-bit
	 * 		 intensity_stereo	MS_stereo
	 * '00'	 off				off
	 * '01'	 on					off
	 * '10'	 off				on
	 * '11'	 on					on
	 */
	private int mode_extension;

	private int framesize;
	private int maindatasize;
	private int sideinfosize;
	private int lsf;
	private boolean isMS, isIntensity;
	
	public Header(byte[] headdata){
		this.headdata=headdata;
	}
	
	public boolean parseHeader(){
		if (headdata==null||headdata.length!=4)
			return false;
		
		int h=byte2int(headdata,0);

		if ((h&0xfff00000)!=0xfff00000)
			return false;
		
		verID = (h >> 19) & 3;
		layer = 4 - ((h >> 17) & 3);
		protection_bit = (h >> 16) & 0x1;
		bitrate_index = (h >> 12) & 0xF;
		sampling_frequency = (h >> 10) & 3;
		padding = (h >> 9) & 0x1;
		mode = (h >> 6) & 3;
		mode_extension = (h >> 4) & 3;

		isMS = mode == 1 && (mode_extension & 2) != 0;
		isIntensity = mode == 1 && (mode_extension & 0x1) != 0;
		lsf = (verID == MPEG1) ? 0 : 1;

		switch (layer) {
		case 1:	
			framesize = bitrate[lsf][0][bitrate_index] * 12000;
			framesize /= samplingRate[verID][sampling_frequency];
			framesize += padding;
			framesize <<= 2; // 1-slot = 4-byte
			break;
		case 2:
			framesize  = bitrate[lsf][1][bitrate_index] * 144000;
			framesize /= samplingRate[verID][sampling_frequency];
			framesize += padding;
			break;
		case 3:
			framesize = bitrate[lsf][2][bitrate_index] * 144000;
			framesize /= samplingRate[verID][sampling_frequency] << lsf;
			framesize += padding;

			//计算帧边信息长度
			if(verID == MPEG1)
				sideinfosize = (mode == 3) ? 17 : 32;
			else
				sideinfosize = (mode == 3) ? 9 : 17;
			break;
		}

		//计算主数据长度
		maindatasize = framesize - 4 - sideinfosize;

		if(protection_bit == 0)
			maindatasize -= 2;	//CRC-word

		return true;
	}
	
	public static String byteToString(byte[] b){
		StringBuilder sb=new StringBuilder();
		for (byte bb:b){
			sb.append(byteToString(bb));
			sb.append("  ");
		}
		return sb.toString();
	}
	
	public static String byteToString(byte b){
		int mask=0x00000080;
		StringBuilder sb=new StringBuilder();
		for (int i=0;i<8;i++){
			sb.append((b&mask)==0?'0':'1');
			if (i==3)
				sb.append(' ');
			mask>>=1;
		}
		return sb.toString();
	}
	
	public static String byteToString(int b){
		int mask=0x1;
		StringBuilder sb=new StringBuilder();
		for (int i=0;i<32;i++){
			sb.insert(0,(b&mask)==0?'0':'1');
			if (i%4==3)
				sb.insert(0,' ');
			mask=mask<<1;
		}
		return sb.toString();
	}
	
	
	private int byte2int(byte[] b, int off) {
		int val = b[off] << 24;
		val |= (b[off + 1] & 0xff) << 16;
		val |= (b[off + 2] & 0xff) << 8;
		val |= (b[off + 3] & 0xff);
		return val;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		byte b=(byte)0xff;
		System.out.println(byteToString(0xfff00000));

	}

}
